package main

import (
	"fmt"
	"time"
)

func main() {
	// 1. 基本用法：随机选择可执行的 case
	ch1 := make(chan int, 1)
	ch2 := make(chan int, 1)
	ch1 <- 1
	ch2 <- 2

	/*
		执行规则：
			select 会同时检查所有 case 语句，select 不会真正执行 case 后面的通道操作，而是检查这些操作是否能够立即完成。
			如果有多个 case 可以执行（通道操作非阻塞），会随机选择一个执行
			如果没有 case 可以执行，且存在 default，则执行 default
			如果没有 case 可以执行，且没有 default，则 select 会阻塞，直到某个 case 可以执行为止
	*/
	select {
	case v := <-ch1:
		fmt.Println("从 ch1 接收:", v)
	case v := <-ch2:
		fmt.Println("从 ch2 接收:", v)
	}

	// 2. 非阻塞接收
	ch3 := make(chan int)
	select {
	case v := <-ch3:
		fmt.Println("从 ch3 接收:", v)
	default:
		fmt.Println("ch3 没有数据可接收")
	}

	// 3. 非阻塞发送
	ch4 := make(chan int, 1)
	ch4 <- 3 // 填满缓冲区
	select {
	case ch4 <- 4:
		fmt.Println("发送 4 到 ch4 成功")
	default:
		fmt.Println("ch4 缓冲区已满，发送失败")
	}

	// 4. 超时控制
	ch5 := make(chan int)
	go func() {
		time.Sleep(2 * time.Second)
		ch5 <- 5
	}()

	select {
	case v := <-ch5:
		fmt.Println("从 ch5 接收:", v)
	case <-time.After(1 * time.Second):
		fmt.Println("等待 ch5 超时")
	}

	// 5. 退出机制
	quit := make(chan bool)
	dataCh := make(chan int)

	go func() {
		for i := 0; i < 3; i++ {
			dataCh <- i
			time.Sleep(500 * time.Millisecond)
		}
		quit <- true
	}()

loop:
	//这种带标签的 break 语句在 Go 语言中是一种常见的流程控制方式，特别适用于需要从多层嵌套结构中跳出的场景。
	//在 for 循环中，使用 break loop 可以直接跳出外层的 for 循环，而不是只是跳出当前的 select 语句。
	for {
		select {
		case v := <-dataCh:
			fmt.Println("处理数据:", v)
		case <-quit:
			fmt.Println("收到退出信号，退出循环")
			break loop
			//如果只是break，则只退出当前select，继续执行下一次select，不会跳出for
		}
	}
}
